home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr22 / edconfig.zip / CONFIG.ASM next >
Assembly Source File  |  1993-05-25  |  42KB  |  978 lines

  1. ;----------------------------------------------------------------;
  2. ;  CONFIG.CTL - Allows you to dynamically change your CONFIG.SYS ;
  3. ;  configuration at boot time.  Add DEVICE = CONFIG.CTL [m]      ;
  4. ;  to your CONFIG.SYS just ahead of the first command you wish   ;
  5. ;  to be able to modify.  m is seconds CONFIG.CTL will pause     ;
  6. ;  for a keystroke before booting normally.  m defaults to zero. ;
  7. ;  Add DEVICE = CONFIG.END after the last command you wish to be ;
  8. ;  able to modify.  CONFIG.END is a dummy device and must appear ;
  9. ;  in CONFIG.SYS in order for CONFIG.CTL to operate.             ;
  10. ;                                                                ;
  11. ;  CONFIG.CTL 1.0 (C) 1988 Ziff Communications Co.
  12. ;----------------------------------------------------------------;
  13.  
  14. _TEXT          SEGMENT PUBLIC 'CODE'          ;********************************;
  15.                ASSUME  CS:_TEXT,DS:_TEXT      ;*                              *;
  16.                ASSUME  ES:_TEXT,SS:_TEXT      ;*  Requires MASM 2.0 or later  *;
  17.                                               ;*     Remember to EXE2BIN      *;
  18.                ORG     0H                     ;*                              *;
  19.                                               ;********************************;
  20.  
  21. ;COPYRIGHT      DB      "CONFIG.CTL 1.1 (c) 1988 Ziff Communications Co.",CR,LF
  22. ;PROGRAMMER     DB      "PC Magazine ",BOX," Michael J. Mefford",CR,LF,CTRL_Z
  23.  
  24. ;************* DEVICE_HEADER *************;
  25.  
  26. POINTER        DD      -1
  27. ATTRIBUTE      DW      1000000000000000B
  28. DEVICE_STAG    DW      STRATEGY
  29. DEVICE_INT     DW      INTERRUPT
  30. DEVICE_NAME    DB      "CONFIGURE"
  31.  
  32.  
  33. CR             EQU     13
  34. LF             EQU     10
  35. CTRL_Z         EQU     26
  36. SPACE          EQU     32
  37. COMMA          EQU     44
  38. FORWARD_SLASH  EQU     47
  39. BOX            EQU     254
  40.  
  41. ;-------------------------;
  42.  
  43. REQUEST_HEADER STRUC
  44.  
  45. HEADER_LENGTH  DB      ?
  46. UNIT_CODE      DB      ?
  47. COMMAND_CODE   DB      ?
  48. STATUS         DW      ?
  49. RESERVED       DQ      ?
  50.  
  51. REQUEST_HEADER ENDS
  52.  
  53. DONE           EQU     0000000100000000B       ;Status codes.
  54. UNKNOWN_CMD    EQU     1000000000000011B
  55.  
  56. ;-------------------------;
  57.  
  58. INIT           STRUC
  59.  
  60. HEADER         DB      (TYPE REQUEST_HEADER) DUP(?)
  61. UNITS          DB      ?
  62. ENDING_OFFSET  DW      ?
  63. ENDING_SEGMENT DW      ?
  64. ARGUMENTS_OFF  DW      ?
  65. ARGUMENTS_SEG  DW      ?
  66.  
  67. INIT           ENDS
  68.  
  69. REQUEST_OFFSET DW      ?
  70. REQUEST_SEG    DW      ?
  71.  
  72. ;              CODE AREA
  73. ;              ---------
  74.  
  75. ;-----------------------------------------------------------------------------;
  76. ; The only task of the strategy is to save the pointer to the request header. ;
  77. ;-----------------------------------------------------------------------------;
  78.  
  79. STRATEGY       PROC    FAR
  80.  
  81.                MOV     CS:REQUEST_OFFSET,BX    ;Request header address is
  82.                MOV     CS:REQUEST_SEG,ES       ; passed in ES:BX.
  83.                RET
  84.  
  85. STRATEGY       ENDP
  86.  
  87. ;------------------------------------------------------------------------;
  88. ; The interrupt procedure will be called immediately after the strategy. ;
  89. ;------------------------------------------------------------------------;
  90.  
  91. INTERRUPT      PROC    FAR
  92.  
  93.                PUSH    AX                      ;Responsible for all registers.
  94.                PUSH    BX
  95.                PUSH    CX
  96.                PUSH    DX
  97.                PUSH    DS
  98.                PUSHF
  99.  
  100.                MOV     DS,CS:REQUEST_SEG       ;Retrieve request header pointer.
  101.                MOV     BX,CS:REQUEST_OFFSET
  102.  
  103.                OR      STATUS[BX],DONE         ;Tell DOS we are done.
  104.                CMP     COMMAND_CODE[BX],0      ;Is it INIT command?
  105.                JZ      MAKE_STACK              ;If yes, do our stuff.
  106.                OR      STATUS[BX],UNKNOWN_CMD  ;Else, exit with confused
  107.                JMP     SHORT UNKNOWN_EXIT      ; message to DOS.
  108.  
  109. MAKE_STACK:    MOV     CX,SS                   ;Save DOS stack.
  110.                MOV     DX,SP
  111.                MOV     AX,CS
  112.                CLI
  113.                MOV     SS,AX                   ;Make new stack.
  114.                MOV     SP,0FFFEH
  115.                STI
  116.                PUSH    CX                      ;Save old stack pointers on new.
  117.                PUSH    DX
  118.  
  119.                PUSH    ES                      ;Save rest of registers.
  120.                PUSH    SI
  121.                PUSH    DI
  122.                PUSH    BP
  123.  
  124.                CALL    INITIALIZE              ;Go do our stuff.
  125.  
  126.                POP     BP                      ;Restore registers.
  127.                POP     DI
  128.                POP     SI
  129.                POP     ES
  130.  
  131.                POP     DX                      ;Restore old DOS stack.
  132.                POP     CX
  133.                CLI
  134.                MOV     SS,CX
  135.                MOV     SP,DX
  136.                STI
  137.  
  138. UNKNOWN_EXIT:  POPF                            ;Restore rest of registers.
  139.                POP     DS
  140.                POP     DX
  141.                POP     CX
  142.                POP     BX
  143.                POP     AX
  144.                RET                             ;Far return back to DOS.
  145.  
  146. INTERRUPT      ENDP
  147.  
  148. CONFIG_CTL_END LABEL   WORD
  149.  
  150. ;************* END OF RESIDENT PORTION *************;
  151.  
  152. BUFFER_SEGMENT DW      ?                       ;CONFIG.SYS buffer segment
  153. BUFFER_START   DW      ?                       ; and offset.
  154. BUFFER_END     DW      ?                       ;CONFIG.END address.
  155. END_FLAG       DB      0                       ;CONFIG.END found flag.
  156.  
  157. CONFIG_END     DB      "DCONFIG.END"
  158. CONFIG_END_LEN EQU     $ - CONFIG_END
  159.  
  160. DELAY_MSG      DB      CR,LF,LF,"Press any key if you wish to modify the "
  161.                DB      "CONFIG.SYS configuration.",CR,LF
  162.                DB      "Press Esc for quick bypass of CONFIG.CTL.",CR,LF,LF,"$"
  163. NOT_FOUND_MSG  DB      "DEVICE = CONFIG.END has to be added as a terminating "
  164.                DB      CR,LF
  165.                DB      "command in CONFIG.SYS before CONFIG.CTL can function."
  166.                DB      CR,LF
  167.                DB      "Press and key to continue.$"
  168. WRONG_VERSION  DB      "Requires DOS 2.x or greater.$"
  169.  
  170. ;--------------------------;
  171.  
  172. NORMAL         EQU     07H                     ;Screen attributes.
  173. INVERSE        EQU     70H
  174.  
  175. HEADING        LABEL   BYTE
  176.  
  177. DB "CONFIG.CTL 1.1 (c) 1988 Ziff Communications Co.",CR,LF
  178. DB "PC Magazine ",BOX," Michael J. Mefford",CR,LF,LF
  179.  
  180. DB "Press F1 to toggle active state of highlighted command.",CR,LF
  181. DB "You may optionally edit a highlighted command.",CR,LF
  182. DB "Press F2 to accept changes and exit.",CR,LF
  183. DB "Press Esc to abort changes and exit.",CR,LF
  184. DB "Note: Permanent changes are not made to the CONFIG.SYS file.$"
  185.  
  186. ;----------------------------;
  187.  
  188. STRING_MAX     EQU     80
  189. DISPLAY_MAX    EQU     67
  190. LAST_RECORD    EQU     -1
  191.  
  192. DATA_RECORD    STRUC
  193.  
  194. COMMAND        DB      STRING_MAX DUP (?)
  195. STRING_LENGTH  DW      ?
  196. ADDRESS        DW      ?                       ;Command string address start.
  197.  
  198. DATA_RECORD    ENDS
  199.  
  200. ROW_START      EQU     9
  201. COL_START      EQU     12
  202.  
  203. CODES          DB      "CBQDXFSKL1I"           ;DOS command codes.
  204. CODES_LENGTH   EQU     $ - CODES               ;For example "C" = BREAK
  205. DOS_VERSION    DB      ?
  206. DOS33          EQU     33
  207. DOS4x          EQU     4
  208.  
  209. COMMAND_TABLE  DB      "BREAK"     ,5 DUP (SPACE), "BUFFERS" ,3 DUP (SPACE)
  210.                DB      "COUNTRY"   ,3 DUP (SPACE), "DEVICE"  ,4 DUP (SPACE)
  211.                DB      "FCBS"      ,6 DUP (SPACE), "FILES"   ,5 DUP (SPACE)
  212.                DB      "SHELL"     ,5 DUP (SPACE), "STACKS"  ,4 DUP (SPACE)
  213.                DB      "LASTDRIVE" ,1 DUP (SPACE), "SWITCHES",2 DUP (SPACE)
  214. LAST_COMMAND   DB      "INSTALL"   ,3 DUP (SPACE)
  215. TABLE_END      EQU     $
  216. COMMAND_SIZE   EQU     TABLE_END - LAST_COMMAND
  217.  
  218. INACTIVE       DB      "INACTIVE" ,2 DUP (SPACE)
  219.  
  220. HIGH_BIT       EQU     10000000B
  221.  
  222. ESC_KEY        EQU     01H
  223. ENTER_KEY      EQU     1CH
  224. F1_KEY         EQU     3BH
  225. F2_KEY         EQU     3CH
  226. BACKSPACE_KEY  EQU     0EH
  227. UP_ARROW_KEY   EQU     48H
  228. DN_ARROW_KEY   EQU     50H
  229. LT_ARROW_KEY   EQU     4BH
  230. RT_ARROW_KEY   EQU     4DH
  231. HOME_KEY       EQU     47H
  232. END_KEY        EQU     4FH
  233. PG_UP_KEY      EQU     49H
  234. PG_DN_KEY      EQU     51H
  235.  
  236. BS             EQU     8
  237.  
  238. DISPATCH_KEY   DB      F1_KEY, BACKSPACE_KEY, UP_ARROW_KEY, DN_ARROW_KEY
  239.                DB      LT_ARROW_KEY, RT_ARROW_KEY, HOME_KEY, END_KEY
  240.                DB      PG_UP_KEY, PG_DN_KEY, ENTER_KEY
  241. KEY_COUNT      EQU     $ - DISPATCH_KEY
  242.  
  243. DISPATCH_TABLE DW      F1, BACKSPACE, UP_ARROW, DN_ARROW
  244.                DW      LT_ARROW, RT_ARROW, HOME, END_CURSOR
  245.                DW      PG_UP, PG_DN, DN_ARROW
  246. DISPATCH_END   EQU     $ - 2
  247.  
  248. ;              ***************
  249. ;              * SUBROUTINES *
  250. ;              ***************
  251.  
  252. ;------------------------------------------;
  253. ; INPUT                                    ;
  254. ;   DS:BX points to request header.        ;
  255. ;                                          ;
  256. ;   All registers destroyed.               ;
  257. ;------------------------------------------;
  258.  
  259.  
  260. INITIALIZE     PROC    NEAR
  261.  
  262.                MOV     ENDING_OFFSET[BX],OFFSET CONFIG_CTL_END
  263.                MOV     ENDING_SEGMENT[BX],CS   ;Resident portion setup.
  264.  
  265.                MOV     AX,ARGUMENTS_SEG[BX]    ;Retrieve CONFIG.SYS buffer
  266.                MOV     ES,AX                   ; pointers from INIT table.
  267.                MOV     BX,ARGUMENTS_OFF[BX]
  268.                PUSH    CS                      ;Point to our data.
  269.                POP     DS
  270.                MOV     BUFFER_SEGMENT,ES       ;And save the segment.
  271.                CLD
  272.  
  273.                PUSH    BX                      ;Save CONFIG.SYS buffer pointer.
  274.                MOV     AH,30H                  ;Get DOS version.
  275.                INT     21H
  276.                POP     BX                      ;Retrieve pointer.
  277.                OR      AL,AL                   ;Is it DOS 2.x or greater?
  278.                JNZ     CK_DOS3                 ;If yes, continue.
  279.                MOV     DX,OFFSET WRONG_VERSION ;Else, unsupported.
  280.                CALL    PRINT_STRING
  281.                JMP     INIT_END                ;Exit.
  282. CK_DOS3:       CMP     AL,3                    ;Is it DOS 3.x?
  283.                JNZ     CK_DOS4                 ;If no, check DOS 4.
  284.                CMP     AH,30                   ;Is it DOS 3.30?
  285.                JB      PARSE                   ;If no, done here.
  286.                MOV     DOS_VERSION,DOS33       ;Else, take note.
  287. CK_DOS4:       CMP     AL,4                    ;Is it DOS 4.x?
  288.                JB      PARSE                   ;If no, done here.
  289.                MOV     DOS_VERSION,DOS4x       ;Else, take note.
  290.  
  291. ;------------------------------------;
  292. ; Parse CONFIG.CTL second parameter. ;
  293. ;------------------------------------;
  294.  
  295. PARSE:         XOR     BP,BP                   ;Use BP to store seconds.
  296. NEXT_NUMBER:   MOV     AL,ES:[BX]              ;Retrieve a byte.
  297.                INC     BX                      ;Point to next byte.
  298.                CMP     AL,CR                   ;If carriage return of linefeed,
  299.                JZ      FIND_END                ; found end of parameter.
  300.                CMP     AL,LF
  301.                JZ      FIND_END
  302.                SUB     AL,"0"                  ;ASCII to binary.
  303.                JC      NEXT_NUMBER             ;If not between 0 and 9, skip.
  304.                CMP     AL,9
  305.                JA      NEXT_NUMBER
  306.                CBW                             ;Convert to word.
  307.                XCHG    AX,BP                   ;Swap old and new number.
  308.                MOV     CX,10                   ;Shift to left by multiplying
  309.                MUL     CX                      ; last entry by ten.
  310.                ADD     BP,AX                   ;Add new number and store in BP.
  311.                JMP     SHORT NEXT_NUMBER
  312.  
  313. ;-----------------------------------------------------------------------;
  314. ; Search for dummy CONFIG.END device as signature of end of buffer.     ;
  315. ; If found, replace "D" device code with "Z" unrecognized command code. ;
  316. ;-----------------------------------------------------------------------;
  317.  
  318. FIND_END:      MOV     BUFFER_START,BX         ;Save start of first command.
  319. NEXT_BYTE:     MOV     SI,OFFSET CONFIG_END    ;Point to CONFIG.END.
  320.                MOV     DI,BX                   ;Point to current buffer pos.
  321.                MOV     CX,CONFIG_END_LEN       ;Is it CONFIG.END?
  322.                REPZ    CMPSB
  323.                JZ      FOUND_END               ;If yes, found end.
  324.                INC     BX                          ;Else, increment buff pos.
  325.                CMP     BX,0FFFFH - CONFIG_END_LEN  ;End of segment?
  326.                JNZ     NEXT_BYTE                   ;If no, continue.
  327.                JMP     SHORT PAUSE             ;Else, give up search.
  328.  
  329. FOUND_END:     MOV     END_FLAG,1              ;Flag that we found CONFIG.END.
  330.                MOV     BYTE PTR ES:[BX],"Z"    ;"Z" out CONFIG.END command.
  331.                DEC     BX                      ;Adjust to buffer end
  332.                MOV     BUFFER_END,BX           ; and store.
  333.  
  334. ;-------------------------------------------------------------;
  335. ; See if user pressed key requesting CONFIG.SYS modification. ;
  336. ;-------------------------------------------------------------;
  337.  
  338. PAUSE:         CALL    CK_KEY                  ;Key pressed?
  339.                JNZ     ATTENTION               ;If yes, give attention.
  340.                MOV     CX,BP                   ;Else, retrieve second delay.
  341.                JCXZ    INIT_END                ;If zero, we're done.
  342.                MOV     DX,OFFSET DELAY_MSG     ;Else, display "Press key for
  343.                CALL    PRINT_STRING            ; service" message.
  344.  
  345. WAIT_A_SEC:    CALL    DELAY                   ;Delay a second.
  346. POLL_KEY:      CALL    CK_KEY                  ;Key pressed?
  347.                JNZ     ATTENTION               ;If yes, give attention.
  348.                LOOP    WAIT_A_SEC              ;Else, continue waiting until
  349.                JMP     SHORT INIT_END          ; time out.
  350.  
  351. ;--------------------------------------------------------------;
  352. ; If keystroke other than ESC was pressed and CONFIG.END dummy ;
  353. ; device found, then we're in business; otherwise exit.
  354. ;--------------------------------------------------------------;
  355.  
  356. ATTENTION:     CALL    GET_KEY                 ;Get the keystroke.
  357.                CMP     AH,ESC_KEY              ;Was is Esc?
  358.                JZ      INIT_END                ;If yes, we're done.
  359.                CMP     END_FLAG,1              ;Else, did we find CONFIG.END?
  360.                JZ      CONTINUE                ;If yes, continue.
  361.                MOV     DX,OFFSET NOT_FOUND_MSG ;Else, Display CONFIG.END not
  362.                CALL    PRINT_STRING            ; found message.
  363.                CALL    GET_KEY                 ;Wait for keystroke so it can be
  364.                JMP     SHORT INIT_END          ; read and then exit.
  365.  
  366. CONTINUE:      CALL    BUSINESS                ;Do our thing.
  367.  
  368. INIT_END:      RET                             ;Exit.
  369.  
  370. INITIALIZE     ENDP
  371.  
  372. ;--------------------------------------------;
  373. ;  INPUT                                     ;
  374. ;    DS = CS                                 ;
  375. ;    ES = CONFIG.SYS command buffer segment. ;
  376. ;                                            ;
  377. ;    All registers destroyed.                ;
  378. ;--------------------------------------------;
  379.  
  380. BUSINESS       PROC    NEAR
  381.  
  382.                CALL    CLS                     ;Clear the screen.
  383.                MOV     DX,OFFSET HEADING       ;Display heading messages.
  384.                CALL    PRINT_STRING
  385.  
  386. ;----------------------------------------------------------------------------;
  387. ; Retrieve the commands from CONFIG.SYS buffer and place them in our buffer. ;
  388. ;----------------------------------------------------------------------------;
  389.  
  390.                MOV     SI,BUFFER_START         ;Point to start of commands.
  391.                MOV     DX,BUFFER_END           ;DX = end of buffer.
  392.                MOV     BX,OFFSET DATA_STORAGE  ;Point to our storage.
  393.                PUSH    CS                      ;Destination segment our data.
  394.                POP     ES
  395.                PUSH    BUFFER_SEGMENT          ;Source segment CONFIG.SYS
  396.                POP     DS                      ; command buffer.
  397.  
  398. NEXT_COMMAND:  CMP     SI,DX                   ;End of buffer?
  399.                JAE     COMMAND_END             ;If yes, done here.
  400.                LODSB                           ;Get a byte.
  401.                CMP     AL,CR                   ;Carriage return or linefeed?
  402.                JZ      NEXT_COMMAND            ;If yes, delimiter; skip.
  403.                CMP     AL,LF
  404.                JZ      NEXT_COMMAND
  405.                PUSH    AX                      ;Else, command code character.
  406.                DEC     SI                      ;Adjust pointer.
  407.                MOV     ES:ADDRESS[BX],SI       ;Save starting address.
  408.                MOV     DI,BX                   ;Point to our storage.
  409.                CALL    RETRIEVE                ;Go retrieve the command string.
  410.                POP     AX                      ;Retrieve command code.
  411.                CMP     AL,"Z"                  ;Was it unrecognized "Z" ?
  412.                JZ      NEXT_COMMAND            ;If yes, skip.
  413.                CMP     AL,"0"                  ;Was it a DOS 4 REM?
  414.                JZ      NEXT_COMMAND            ;If yes, skip.
  415.                DEC     CX                      ;Else, adjust string length.
  416.                JLE     NEXT_COMMAND            ;Null string?  If yes, skip.
  417.                MOV     ES:STRING_LENGTH[BX],CX ;Else, store length.
  418.                ADD     BX,TYPE DATA_RECORD     ;Point to next storage record.
  419.                JMP     SHORT NEXT_COMMAND      ;Get next command.
  420.  
  421. COMMAND_END:   PUSH    CS                      ;Back to our data segment.
  422.                POP     DS
  423.                MOV     COMMAND[BX],LAST_RECORD ; -1 as end of data signature.
  424.                CMP     BX,OFFSET DATA_STORAGE  ;Were there any commands?
  425.                JZ      BUSINESS_END            ;If no, done here.
  426.  
  427. ;--------------------------------------------------;
  428. ; Display the commands and let the user edit them. ;
  429. ;--------------------------------------------------;
  430.  
  431.                CALL    DISPLAY_IT
  432.                CALL    EDIT
  433.                JC      BUSINESS_END            ;If carry, Esc was pressed.
  434.  
  435. ;----------------------------------------------------------;
  436. ; Place the edited commands back in the CONFIG.SYS buffer. ;
  437. ;----------------------------------------------------------;
  438.  
  439.                MOV     BX,OFFSET DATA_STORAGE  ;Point to CONFIG.SYS buffer
  440.                PUSH    BUFFER_SEGMENT          ; as destination.
  441.                POP     ES
  442.  
  443. STORE_COMMAND: CMP     COMMAND[BX],LAST_RECORD ;Is it the last record?
  444.                JZ      BUSINESS_END            ;If yes, we're all done.
  445.                TEST    COMMAND[BX],HIGH_BIT    ;Is command inactive?
  446.                JZ      REPLACE_DATA            ;If no, OK.
  447.                MOV     COMMAND[BX],"Z"         ;Else, replace with "Z".
  448. REPLACE_DATA:  MOV     SI,BX                   ;Point to command string.
  449.                MOV     DI,ADDRESS[BX]          ;Point to destination address.
  450.                CALL    REPLACE                 ;Replace the string in buffer.
  451.                ADD     BX,TYPE DATA_RECORD     ;Point to next record.
  452.                JMP     SHORT STORE_COMMAND     ;And store it.
  453.  
  454. BUSINESS_END:  CALL    CLS                     ;Exit with clean slate.
  455.                RET
  456.  
  457. BUSINESS       ENDP
  458.  
  459. ;---------------------------------------;
  460. ; INPUT                                 ;
  461. ;   DS:SI points to CONFIG.SYS buffer.  ;
  462. ;   ES:DI points to our storage.        ;
  463. ;                                       ;
  464. ; OUTPUT                                ;
  465. ;   SI and DI at end of string.         ;
  466. ;   CX = string length include one byte ;
  467. ;   for CR or LF.  ASCIIZ is stripped.  ;
  468. ;                                       ;
  469. ;   AX  destroyed.                      ;
  470. ;---------------------------------------;
  471.  
  472. RETRIEVE       PROC    NEAR
  473.  
  474.                MOV     CX,-1                   ;Initialize counter.
  475.                LODSB                           ;Load and store code.
  476.                MOV     AH,AL                   ;Preserve code.
  477. STORE_IT:      STOSB
  478.                INC     CX
  479.                CMP     AL,CR                   ;If terminating carriage return
  480.                JZ      RETRIEVE_END            ; or linefeed, we're done.
  481.                CMP     AL,LF
  482.                JZ      RETRIEVE_END
  483. NEXT_RETRIEVE: LODSB                           ;Get a byte.
  484.                OR      AL,AL                   ;Is it ASCIIZ zero?
  485.                JNZ     STORE_IT                ;If no, check CR or LF.
  486.                CMP     BYTE PTR [SI],CR        ;Else, end of parameters?
  487.                JBE     NEXT_RETRIEVE           ;If yes, skip.
  488.                CMP     ES:DOS_VERSION,DOS33    ;Else, is it DOS 3.3?
  489.                JZ      NEXT_RETRIEVE           ;If yes, strip all zeros.
  490.                CMP     AH,"S"                  ;Else, is it SHELL ASCIIZ?
  491.                JZ      CONVERT                 ;If yes, convert to space.
  492.                CMP     AH,"D"                  ;Else, is it a DEVICE ASCIIZ?
  493.                JZ      CONVERT                 ;If yes, convert to space.
  494.                CMP     AH,"I"                  ;Else, is it INSTALL?
  495.                JNZ     NEXT_RETRIEVE           ;If no, strip.
  496. CONVERT:       MOV     AL,SPACE                ;Else, convert to space.
  497.                JMP     SHORT STORE_IT
  498. RETRIEVE_END:  RET
  499.  
  500. RETRIEVE       ENDP
  501.  
  502. ;--------------------------------------;
  503. ; INPUT                                ;
  504. ;   DS:SI points to our storage.       ;
  505. ;   ES:DI points to CONFIG.SYS buffer. ;
  506. ;   BX = current record.               ;
  507. ;                                      ;
  508. ; OUTPUT                               ;
  509. ;   ASCIIZ is reinserted in string.    ;
  510. ;   SI and DI at end of string.        ;
  511. ;                                      ;
  512. ;   AX, CX, DX, BP destroyed.          ;
  513. ;--------------------------------------;
  514.  
  515. REPLACE        PROC    NEAR
  516.  
  517.                MOV     CX,STRING_LENGTH[BX]    ;Retrieve string length.
  518.                INC     CX                      ;Include command code byte.
  519.                MOV     BP,-1                   ;ASCIIZ flag.
  520.                XOR     DX,DX                   ;Leading space flag.
  521.                MOV     AH,[SI]                 ;Retrieve code.
  522. NEXT_REPLACE:  LODSB                           ;Get a byte.
  523.                CMP     AL,"a"                  ;Capitalize.
  524.                JB      CK_LEADING
  525.                CMP     AL,"z"
  526.                JA      CK_LEADING
  527.                AND     AL,5FH
  528.  
  529. CK_LEADING:    CMP     AL,SPACE                ;Is it a leading space?
  530.                JNZ     CK_ADD_ZERO             ;If no, check if zero time.
  531.                CMP     DX,1                    ;If command only thing stored
  532.                JZ      NEXT_REPLACE            ; so far, then it's leading.
  533.  
  534. CK_ADD_ZERO:   CMP     BP,-1                   ;Have we stored a zero yet?
  535.                JNZ     CK_CR_LF                ;If yes, check CR and LF.
  536.                CMP     AL,SPACE                ;Else, is it space?
  537.                JZ      CK_DOS                  ;If yes, check of DOS 4.
  538.                CMP     AH,"Q"                  ;Is it COUNTRY?
  539.                JZ      STORE_BYTE              ;If yes, store the space.
  540.                CMP     DOS_VERSION,DOS33       ;Else, is DOS 3.3?
  541.                JNZ     STORE_BYTE              ;If no, store the non space.
  542.                CMP     AL,COMMA                ;Else, is it a comma or slash?
  543.                JZ      ASCIIZ                  ;If yes, ASCIIZ it.
  544.                CMP     AL,FORWARD_SLASH
  545.                JZ      ASCIIZ
  546.                JMP     SHORT STORE_BYTE        ;Else, just store the byte.
  547.  
  548. CK_DOS:        CMP     DOS_VERSION,DOS4x       ;Is it DOS 4?
  549.                JNZ     ASCIIZ                  ;If no, ASCIIZ.
  550.                CMP     AH,"D"                  ;Else, is it DEVICE or SHELL?
  551.                JZ      ASCIIZ                  ;If yes, ASCIIZ.
  552.                CMP     AH,"S"
  553.                JZ      ASCIIZ
  554.                CMP     AH,"I"                  ;Or INSTALL of DOS 4.
  555.                JNZ     STORE_BYTE              ;Else, just store the byte.
  556.  
  557. ASCIIZ:        XCHG    AX,BP                   ;Swap special character.
  558.                XOR     AX,AX                   ;Store the zero.
  559.                STOSB                           ;Retrieve the character and
  560.                XCHG    AX,BP                   ; zero in BP as flag.
  561.                CMP     DOS_VERSION,DOS33       ;Is it DOS 3.3?
  562.                JNZ     BYTE_STORED             ;If yes, store the char also.
  563.  
  564. CK_CR_LF:      CMP     AL,CR                   ;If CR or LF we're done here.
  565.                JZ      PAD_SPACES
  566.                CMP     AL,LF
  567.                JZ      PAD_SPACES
  568.  
  569. STORE_BYTE:    STOSB                           ;Store the byte.
  570. BYTE_STORED:   INC     DX                      ;Increment count.
  571.                LOOP    NEXT_REPLACE
  572.  
  573. PAD_SPACES:    DEC     CX                      ;Throw away CR or LF count.
  574.                JLE     CK_ZERO                 ;If end of string, done.
  575.                MOV     AL,SPACE                ;Else, move leading spaces
  576.                REP     STOSB                   ; to end of string.
  577.  
  578. CK_ZERO:       CMP     BP,-1                   ;Have we replaced a zero yet?
  579.                JNZ     REPLACE_END             ;If yes done.
  580.                CMP     DOS_VERSION,DOS4x       ;Is it DOS 4.x?
  581.                JNZ     ADD_ZERO                ;If no, add a zero.
  582.                CMP     AH,"S"                  ;Else, is it SHELL filename?
  583.                JZ      ADD_ZERO                ;If yes, ASCIIZ.
  584.                CMP     AH,"D"                  ;Else, is it DEVICE filename?
  585.                JZ      ADD_ZERO                ;If yes, ASCIIZ.
  586.                CMP     AH,"I"                  ;Else, is it INSTALL filename?
  587.                JNZ     REPLACE_END             ;If no, done
  588. ADD_ZERO:      XOR     AL,AL                   ;Else, add ASCIIZ.
  589.                STOSB
  590.  
  591. REPLACE_END:   RET
  592.  
  593. REPLACE        ENDP
  594.  
  595. ;------------------------------------------;
  596. ;   Display the commands on the screen.    ;
  597. ;   All registers destroyed.               ;
  598. ;------------------------------------------;
  599.  
  600. DISPLAY_IT     PROC    NEAR
  601.  
  602.                MOV     BP,OFFSET DATA_STORAGE  ;Point to data storage.
  603.                MOV     DH,ROW_START            ;Point to first display row.
  604.  
  605. NEXT_DISPLAY:  XOR     DL,DL                   ;Column zero.
  606.                CALL    SET_CURSOR              ;Set cursor position.
  607.                CMP     COMMAND[BP],LAST_RECORD ;Is it the last record?
  608.                JZ      DISPLAY_END             ;If yes, done here.
  609.                CALL    DECODE                  ;Else, decode the command.
  610.                MOV     AL,"="                  ;Add quotes and a space.
  611.                CALL    WRITE_TTY
  612.                MOV     AL,SPACE
  613.                CALL    WRITE_TTY
  614.                MOV     SI,BP                   ;Point to command string.
  615.                INC     SI
  616.                MOV     CX,STRING_LENGTH[BP]    ;Retrieve the string length.
  617. NEXT_ARGUMENT: LODSB                           ;Display the command.
  618.                CALL    WRITE_TTY
  619.                LOOP    NEXT_ARGUMENT
  620.                ADD     BP,TYPE DATA_RECORD     ;Point to next record.
  621.                INC     DH                      ;Next cursor row.
  622.                CMP     DH,25                   ;Is it row 25?
  623.                JNZ     NEXT_DISPLAY            ;If no, continue.
  624.  
  625. DISPLAY_END:   RET
  626.  
  627. DISPLAY_IT     ENDP
  628.  
  629. ;-----------------------------------------;
  630. ; INPUT                                   ;
  631. ;   BP points to command.                 ;
  632. ;                                         ;
  633. ; OUTPUT                                  ;
  634. ;   The command is decoded and displayed. ;
  635. ;                                         ;
  636. ;   AX, CX, SI and DI destroyed.          ;
  637. ;-----------------------------------------;
  638.  
  639. DECODE         PROC    NEAR
  640.  
  641.                MOV     SI,OFFSET INACTIVE      ;Assume command inactive.
  642.                MOV     AL,COMMAND[BP]          ;Retrieve command.
  643.                TEST    AL,HIGH_BIT             ;Is it marked inactive?
  644.                JNZ     FOUND_COMMAND           ;If yes, assumed right.
  645.                MOV     DI,OFFSET CODES         ;Else, point to codes.
  646.                MOV     CX,CODES_LENGTH         ;Number of codes.
  647.                REPNZ   SCASB                   ;Search for match.
  648.                MOV     SI,OFFSET TABLE_END     ;Point to lookup table.
  649.                INC     CX                      ;Adjust count.
  650. FIND_COMMAND:  SUB     SI,COMMAND_SIZE         ;Point to appropriate command.
  651.                LOOP    FIND_COMMAND
  652.  
  653. FOUND_COMMAND: MOV     CX,COMMAND_SIZE         ;Command string length.
  654. DISPLAY_CMD:   LODSB                           ;Display it.
  655.                CALL    WRITE_TTY
  656.                LOOP    DISPLAY_CMD
  657.                RET
  658.  
  659. DECODE         ENDP
  660.  
  661. ;----------------------------------;
  662. ;  OUTPUT                          ;
  663. ;    Carry flag = 0 if good edit.  ;
  664. ;    Carry flag = 1 if edit abort. ;
  665. ;                                  ;
  666. ;    All registers destroyed.      ;
  667. ;----------------------------------;
  668.  
  669. EDIT           PROC    NEAR
  670.  
  671.                MOV     BP,OFFSET DATA_STORAGE  ;Point to data storage.
  672.                MOV     DH,ROW_START            ;Point to first row.
  673.                MOV     BL,INVERSE              ;Highlight the first command.
  674.                CALL    HIGHLIGHT_BAR           ;Return with DI = 1; first char.
  675.  
  676. NEXT_KEY:      CALL    GET_KEY                 ;Get a keystroke.
  677.                CMP     AH,ESC_KEY              ;Is it ESC?
  678.                JZ      NO_CHANGE               ;If yes, exit with no change.
  679.                CMP     AH,F2_KEY               ;Is it F2?
  680.                JZ      EDIT_END                ;If yes, exit with changes.
  681.                CMP     AL,BS                   ;Is it backspace?
  682.                JZ      FUNCTION                ;If yes, function.
  683.                CMP     AL,CR                   ;Is it carriage return?
  684.                JZ      FUNCTION                ;If yes, function.
  685.                CMP     AH,F1_KEY               ;Is it F1 or above?
  686.                JAE     FUNCTION                ;If yes, function.
  687.  
  688. ASCII:         CMP     AL,SPACE                ;Is it space or above?
  689.                JB      NEXT_KEY                ;If no, skip.
  690.                CMP     DI,STRING_LENGTH[BP]    ;Else, are we at end of field?
  691.                JA      NEXT_KEY                ;If yes, skip.
  692.                MOV     COMMAND[BP+DI],AL       ;Else, store character.
  693.                INC     DI                      ;Point to next storage.
  694.                INC     DL                      ;Increment cursor column.
  695.                CALL    WRITE_TTY               ;Write the character to screen.
  696.                JMP     SHORT NEXT_KEY          ;Get next keystroke.
  697.  
  698. FUNCTION:      MOV     AL,AH                   ;Scan code in AL.
  699.                MOV     CX,KEY_COUNT            ;Count of active functions.
  700.                PUSH    DI                      ;Preserve DI.
  701.                MOV     DI,OFFSET DISPATCH_KEY  ;Point to active keys.
  702.                REPNZ   SCASB                   ;Scan for match.
  703.                POP     DI                      ;Retrieve DI.
  704.                JNZ     NEXT_KEY                ;If no match, next key.
  705.                MOV     SI,OFFSET DISPATCH_END  ;Else, point to dispatch table.
  706.                SHL     CX,1                    ;Convert to word offset.
  707.                SUB     SI,CX                   ;Point to appropriate procedure
  708.                CALL    DS:[SI]                 ; and go do it.
  709.                JMP     SHORT NEXT_KEY          ;Get next keystroke.
  710.  
  711. NO_CHANGE:     STC
  712. EDIT_END:      RET
  713.  
  714. EDIT           ENDP
  715.  
  716. ;----------------------------------------------------------------------------; 
  717. ; The following are the active function, arrow and backspace key procedures. ;
  718. ;----------------------------------------------------------------------------;
  719.  
  720. F1             PROC    NEAR
  721.  
  722.                PUSH    DI                      ;Preserve DI and DX.
  723.                PUSH    DX
  724.                XOR     DL,DL                   ;Column zero.
  725.                CALL    SET_CURSOR              ;Set cursor.
  726.                XOR     COMMAND[BP],HIGH_BIT    ;Toggle active state.
  727.                CALL    DECODE                  ;Decode the command.
  728.                POP     DX                      ;Restore cursor position.
  729.                CALL    SET_CURSOR
  730.                POP     DI                      ;Restore DI.
  731.                RET
  732.  
  733. F1             ENDP
  734.  
  735. ;------------------------------;
  736.  
  737. BACKSPACE      PROC    NEAR
  738.  
  739.                CMP     DI,1                    ;Are we already at first char?
  740.                JZ      BACKSPACE_END           ;If yes, skip.
  741.                DEC     DL                      ;Else, decrement cursor
  742.                DEC     DI                      ; and character storage position.
  743.                MOV     COMMAND[BP+DI],SPACE    ;Store a space.
  744.                MOV     AL,BS                   ;Write a backspace, space and
  745.                CALL    WRITE_TTY               ;backspace to screen.
  746.                MOV     AL,SPACE
  747.                CALL    WRITE_TTY
  748.                MOV     AL,BS
  749.                CALL    WRITE_TTY
  750. BACKSPACE_END: RET
  751.  
  752. BACKSPACE      ENDP
  753.  
  754. ;------------------------------;
  755.  
  756. UP_ARROW       PROC    NEAR
  757.  
  758.                CMP     BP,OFFSET DATA_STORAGE  ;Are we already at top row?
  759.                JZ      UP_ARROW_END            ;If yes, skip.
  760.                MOV     BL,NORMAL               ;Else, return to normal
  761.                CALL    HIGHLIGHT_BAR           ; attribute current row.
  762.                SUB     BP,TYPE DATA_RECORD     ;Move up a record.
  763.                DEC     DH                      ;Move cursor up one.
  764.                MOV     BL,INVERSE              ;Display line in inverse video.
  765.                CALL    HIGHLIGHT_BAR
  766. UP_ARROW_END:  RET
  767.  
  768. UP_ARROW       ENDP
  769.  
  770. ;------------------------------;
  771.  
  772. DN_ARROW       PROC    NEAR
  773.  
  774.                CMP     COMMAND[BP+TYPE DATA_RECORD],LAST_RECORD
  775.                JZ      DN_ARROW_END
  776.                CMP     DH,24                   ;If last record already or
  777.                JZ      DN_ARROW_END            ; bottom of screen, skip.
  778.                MOV     BL,NORMAL               ;Else, return current row to
  779.                CALL    HIGHLIGHT_BAR           ; normal.
  780.                ADD     BP,TYPE DATA_RECORD     ;Go down a record.
  781.                INC     DH                      ;And down a row.
  782.                MOV     BL,INVERSE              ;Display the line inverse video.
  783.                CALL    HIGHLIGHT_BAR
  784. DN_ARROW_END:  RET
  785.  
  786. DN_ARROW       ENDP
  787.  
  788. ;------------------------------;
  789.  
  790. LT_ARROW       PROC    NEAR
  791.  
  792.                CMP     DI,1                    ;Are we already first positon?
  793.                JZ      LT_ARROW_END            ;If yes, skip.
  794.                DEC     DI                      ;Else, decrement storage position
  795.                DEC     DL                      ; and cursor position.
  796.                CALL    SET_CURSOR
  797. LT_ARROW_END:  RET
  798.  
  799. LT_ARROW       ENDP
  800.  
  801. ;------------------------------;
  802.  
  803. RT_ARROW       PROC    NEAR
  804.  
  805.                CMP     DI,STRING_LENGTH[BP]    ;Are we already end of string?
  806.                JA      RT_ARROW_END            ;If yes, skip.
  807.                INC     DI                      ;Else, increment storage position
  808.                INC     DL                      ; and cursor position.
  809.                CALL    SET_CURSOR
  810. RT_ARROW_END:  RET
  811.  
  812. RT_ARROW       ENDP
  813.  
  814. ;------------------------------;
  815.  
  816. HOME           PROC    NEAR
  817.  
  818.                MOV     DI,1                    ;Home storage position
  819.                MOV     DL,COL_START            ; and cursor.
  820.                CALL    SET_CURSOR
  821.                RET
  822.  
  823. HOME           ENDP
  824.  
  825. ;------------------------------;
  826.  
  827. END_CURSOR     PROC    NEAR
  828.  
  829.                MOV     DI,STRING_LENGTH[BP]    ;Retrieve string length.
  830.                MOV     CX,DI
  831.                MOV     DL,CL
  832.                ADD     DL,COL_START            ;Add to starting column.
  833.                INC     DI                      ;Adjust.
  834.                CALL    SET_CURSOR              ;Set cursor.
  835.                RET
  836.  
  837. END_CURSOR     ENDP
  838.  
  839. ;------------------------------;
  840.  
  841. PG_DN          PROC    NEAR
  842.  
  843.                MOV     BL,NORMAL               ;Current postion back to normal.
  844.                CALL    HIGHLIGHT_BAR
  845. NEXT_PG_DN:    CMP     COMMAND[BP+TYPE DATA_RECORD],LAST_RECORD
  846.                JZ      PAGE_END
  847.                ADD     BP,TYPE DATA_RECORD     ;If not already last position,
  848.                INC     DH                      ; go to it.
  849.                JMP     SHORT NEXT_PG_DN
  850. PAGE_END:      MOV     BL,INVERSE              ;And display it in inverse video.
  851.                CALL    HIGHLIGHT_BAR
  852.                RET
  853.  
  854. PG_DN          ENDP
  855.  
  856. ;------------------------------;
  857.  
  858. PG_UP          PROC    NEAR
  859.  
  860.                MOV     BL,NORMAL               ;Restore current position to
  861.                CALL    HIGHLIGHT_BAR           ; normal.
  862.                MOV     BP,OFFSET DATA_STORAGE  ;Move to top command.
  863.                MOV     DH,ROW_START            ;And cursor position.
  864.                MOV     BL,INVERSE              ;And highlight.
  865.                CALL    HIGHLIGHT_BAR
  866.                RET
  867.  
  868. PG_UP          ENDP
  869.  
  870. ;------------------------------------------;
  871. ; INPUT                                    ;
  872. ;   BL = attribute.                        ;
  873. ;   BP points to current command.          ;
  874. ;                                          ;
  875. ; OUTPUT                                   ;
  876. ;   DI = 1 (First storage position.)       ;
  877. ;   DL = cursor column start.              ;
  878. ;                                          ;
  879. ;   CX, SI destroyed.                      ;
  880. ;------------------------------------------;
  881.  
  882. HIGHLIGHT_BAR  PROC    NEAR
  883.  
  884.                MOV     CX,STRING_LENGTH[BP]    ;Retrieve string length.
  885.                MOV     SI,BP                   ;Point to command.
  886.                INC     SI                      ;Adjust.
  887.                MOV     DL,COL_START            ;Point to first position.
  888. HIGHLIGHT:     CALL    SET_CURSOR              ;Set the cursor.
  889.                LODSB
  890.                PUSH    CX                      ;Preserve CX.
  891.                MOV     CX,1
  892.                MOV     AH,9                    ;Write char/attribute.
  893.                INT     10H
  894.                INC     DL                      ;Increment cursor postion.
  895.                POP     CX
  896.                LOOP    HIGHLIGHT
  897.                MOV     DL,COL_START            ;Point to first position again.
  898.                CALL    SET_CURSOR              ;Set cursor.
  899.                MOV     DI,1                    ;Return with DI = first storage.
  900.                RET
  901.  
  902. HIGHLIGHT_BAR  ENDP
  903.  
  904. ;---------------------------------------; 
  905. ; The following are support procedures. ;
  906. ;---------------------------------------;
  907.  
  908. WRITE_TTY      PROC    NEAR
  909.  
  910.                MOV     AH,0EH                  ;Write TTY via BIOS.
  911.                INT     10H
  912.                RET
  913.  
  914. WRITE_TTY      ENDP
  915.  
  916. ;------------------------------;
  917.  
  918. SET_CURSOR     PROC    NEAR
  919.  
  920.                XOR     BH,BH                   ;Enter with DX = cursor postion.
  921.                MOV     AH,2                    ;Set cursor position via BIOS.
  922.                INT     10H
  923.                RET
  924.  
  925. SET_CURSOR     ENDP
  926.  
  927. ;------------------------------;
  928.  
  929. CLS            PROC    NEAR
  930.  
  931.                MOV     AH,0FH                  ;Get current video mode.
  932.                INT     10H
  933.                XOR     AH,AH                   ;Set current video mode.
  934.                INT     10H                     ;Result is a clear screen.
  935.                RET
  936.  
  937. CLS            ENDP
  938.  
  939. ;------------------------------;
  940.  
  941. DELAY          PROC    NEAR
  942.  
  943.                PUSH    DS                      ;Preserve data segment.
  944.                MOV     AX,40H                  ;Point to BIOS data segment.
  945.                MOV     DS,AX
  946.                MOV     AX,DS:[6CH]             ;Retrieve timer low.
  947.                ADD     AX,18                   ;Add 18 counts per second.
  948. NEXT_COUNT:    MOV     DX,DS:[6CH]             ;Retrieve timer low.
  949.                CMP     DX,AX                   ;Have we timed out?
  950.                JNZ     NEXT_COUNT              ;If not, wait until second up.
  951.                POP     DS                      ;Restore data segment.
  952.                RET
  953.  
  954. DELAY          ENDP
  955.  
  956. ;------------------------------;
  957.  
  958. GET_KEY:       MOV     AH,0                    ;Retrieve keystroke via BIOS.
  959.                INT     16H
  960.                RET
  961.  
  962. CK_KEY:        MOV     AH,1                    ;Check for keystroke via BIOS.
  963.                INT     16H
  964.                RET
  965.  
  966. ;------------------------------;
  967.  
  968. PRINT_STRING:  MOV     AH,9                    ;Print string via DOS.
  969.                INT     21H
  970.                RET
  971.  
  972. ;------------------------------;
  973.  
  974. DATA_STORAGE   EQU     $
  975.  
  976. _TEXT          ENDS
  977.                END
  978.